# Copyright (C) 2008 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import string
import logging

import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.api import users
from google.appengine.ext.webapp import template
from google.appengine.api import mail

import accounts
import models


SENDER_EMAIL = 'wave.sandbox.form@gmail.com'
BCC_EMAIL = 'pamela.fox@gmail.com'
ATTEMPT_MAX = 99999


class AvailabilityHandler(webapp.RequestHandler):
  """A web service that responds with 'yes', 'no', or 'error'."""

  def get(self):
    username = self.request.get('username')
    check = accounts.CheckAvailability(username)
    self.response.out.write(check)


class FormHandler(webapp.RequestHandler):
  """A web page showing the signup form + logout URL."""

  def get(self):
    email = users.get_current_user().email()
    username = email.split('@')[0]
    url = users.create_logout_url(self.request.uri)
    template_values = {'username': username, 'url': url}
    path = os.path.join(os.path.dirname(__file__), 'templates/index.html')
    self.response.out.write(template.render(path, template_values))


class FormSignHandler(webapp.RequestHandler):
  """A web handler for the signup form action. Creates a new entity in
  datastore for the request, if username is available. Otherwise, shows error."""

  def post(self):
    MESSAGE_INVALID = """That username is not available. Please <a href="/">sign
                         up</a> again, and use the check availability button before
                         submitting."""
    MESSAGE_SUCCESS = """Thanks for requesting. You should be notified
                       of new account info by email in the next 30 minutes."""

    username = self.request.get('choice')

    # First, check to make sure the username is available and valid.
    # (Some people may not have checked availability before submitting.)
    check = accounts.CheckAvailability(username)
    if check == 'no':
      template_values = {'message': MESSAGE_INVALID}
      path = os.path.join(os.path.dirname(__file__), 'templates/message.html')
      self.response.out.write(template.render(path, template_values))
      return

    # If it's all good, store the request in the datastore.
    signer_data = {}
    fields = ['first_name', 'last_name', 'choice']
    for field in fields:
      signer_data[field] = self.request.get(field)
    signer_model = models.SignerModel()
    signer_model.first_name = signer_data['first_name']
    signer_model.last_name = signer_data['last_name']
    signer_model.choice = signer_data['choice']
    signer_model.attempted = 0
    signer_model.created = False
    signer_model.user = users.get_current_user()
    signer_model.put()
    template_values = {'message': MESSAGE_SUCCESS}
    path = os.path.join(os.path.dirname(__file__), 'templates/message.html')
    self.response.out.write(template.render(path, template_values))


class SignupRequestHandler(webapp.RequestHandler):
  """A web service that attempts to create an account based on requests in the
  datastore. If it succeeds, it sends an email with the details. If it errors
  and the error is caused by the user, it sends an email asking to retry.
  This service is designed to be called by a cron job."""

  def isInvalid(self, signer_model):
    account_name = signer_model.choice
    if not accounts.CheckValidity(account_name):
      logging.info('%s is not a valid account name' % account_name)
      signer_model.attempted = ATTEMPT_MAX
      signer_model.put()
      self.sendUserErrorEmail(signer_model)
      return True

    if accounts.CheckAvailability(account_name) == 'no':
      logging.info('%s already exists' % account_name)
      signer_model.attempted = ATTEMPT_MAX
      signer_model.put()
      self.sendUserErrorEmail(signer_model)
      return True

    return False


  def get(self):
    # Fetch the un-fulfilled requests, sorted so that unattempted requests are
    # processed first.
    query = models.SignerModel().all()
    query.filter('created = ', False)
    query.order('attempted')
    signer_model = query.get()

    # If there is no result, there is nothing in the queue to process.
    if signer_model is None:
      return

    # If an error has already been recorded and the user notified
    if signer_model.attempted == ATTEMPT_MAX:
      logging.info('Returning. This one is in error')
      return

    # If the request has been attempted more than twice, check if the
    # request is invalid, and if so, do not continue
    if signer_model.attempted > 1 and self.isInvalid(signer_model):
      return

    request = accounts.CreateAccountFromModel(signer_model)
    if signer_model.created:
      self.sendUserApprovalEmail(signer_model)
      logging.info('Sending mail for new account %s' % signer_model.username)
    else:
      # There was an error in creating.
      signer_model.attempted += 1
      signer_model.put()
      logging.info('Attempted but failed %s' % signer_model.choice)

  def sendUserErrorEmail(self, signer):
    subject = 'WaveSandbox.com Account: Error Creating'

    body = 'We were unable to create your account, either due to an invalid \
      or duplicate account name. Please try creating a new account.'
    receiver_email = signer.user.email()

    mail.send_mail(SENDER_EMAIL, receiver_email, subject, body, bcc=BCC_EMAIL)

  def sendUserApprovalEmail(self, signer):
    template_name = 'success.eml'
    subject = 'WaveSandbox.com Account'

    body = self.renderEmail(signer, template_name)
    receiver_email = signer.user.email()

    mail.send_mail(SENDER_EMAIL, receiver_email, subject, body, bcc=BCC_EMAIL)


  def renderEmail(self, signer, template_name, values={}):
    values['username'] = signer.username
    values['password'] = signer.password
    directory = os.path.dirname(os.environ['PATH_TRANSLATED'])
    path = os.path.join(directory, 'templates/' + template_name)
    return template.render(path, values)

def main():
  application = webapp.WSGIApplication([('/', FormHandler),
                                        ('/sign', FormSignHandler),
                                        ('/availability', AvailabilityHandler),
                                        ('/process', SignupRequestHandler),
                                       ], debug=True)
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
  main()
